package at.donalfonso.ui.group;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.mozartspaces.core.ContainerReference;
import org.mozartspaces.core.Entry;
import org.mozartspaces.core.MzsCoreException;
import org.mozartspaces.notifications.Notification;
import org.mozartspaces.notifications.NotificationListener;
import org.mozartspaces.notifications.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.donalfonso.kunde.KundeThread;
import at.donalfonso.model.Gruppe;
import at.donalfonso.model.LieferKunde;
import at.donalfonso.utility.SpaceUtility;

public class GroupController implements NotificationListener, WindowListener, ActionListener {

	private ArrayList<Gruppe> groupsQueue = new ArrayList<Gruppe>();
		
	private GroupView view = null;
	private SpaceUtility filiale1 = null;
	private SpaceUtility filiale2 = null;
	
	private ArrayList<GruppeThread> threads = new ArrayList<GruppeThread>();
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {

		new GroupController();

	}
	
	public GroupController() {
		
		try {
			//"com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {

			e.printStackTrace();
		}

		view = new GroupView(this);		
		view.addWindowListener(this);
		view.setTitle("Don Alfonso: GruppenGUI XVSM");
	
		filiale1 = new SpaceUtility(1);
		filiale2 = new SpaceUtility(2);
		
		// Eigener Space für Lieferkunden existiert global für alle Filialen
		filiale1.createLieferCore();
		
		try {
			filiale1.getNotificationManager().createNotification(filiale1.getEingangContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getSaalContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeSitzenContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeWillBestellenContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeHatBestelltContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeEssenContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeWillBezahlenContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeHatBezahltContainer(), this, Operation.WRITE);
			filiale1.getNotificationManager().createNotification(filiale1.getGruppeGegangenContainer(), this, Operation.WRITE);

			filiale2.getNotificationManager().createNotification(filiale2.getEingangContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getSaalContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeSitzenContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeWillBestellenContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeHatBestelltContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeEssenContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeWillBezahlenContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeHatBezahltContainer(), this, Operation.WRITE);
			filiale2.getNotificationManager().createNotification(filiale2.getGruppeGegangenContainer(), this, Operation.WRITE);

		} catch (MzsCoreException | InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
		

	public void addGroup(Gruppe group){
		groupsQueue.add(group);
	}
	
	/**
	 * Schickt die Gruppen in der Queue in den Space. 
	 */
	public void sendGroupsToSpace() { 
		
		DefaultListModel<Gruppe> model = view.getGroupQueueModel();
		Enumeration<Gruppe> queue = model.elements();
		
		while (queue.hasMoreElements()) {
			Gruppe group = queue.nextElement();
			if (group instanceof LieferKunde) {
				// Lieferung
				logger.debug("Thread für LieferKunde " + group.getId() + " wird gestartet.");				
				KundeThread t = new KundeThread((LieferKunde) group);
				threads.add(t);
				t.start();
				logger.debug("Thread für LieferKunde " + group.getId() + " gestartet.");
			} 
			else {
				// Restaurantbesucher
				logger.debug("Thread für Gruppe " + group.getId() + " wird gestartet.");				
				GruppeThread t = new GruppeThread(group);
				threads.add(t);
				t.start();
				logger.debug("Thread für Gruppe " + group.getId() + " gestartet.");
			}
		}

		// Die Queue wird geleert.
		model.removeAllElements();
	}


	@Override
	public void entryOperationFinished(Notification noti, Operation op,
			List<? extends Serializable> entries) {
		logger.debug("processing XVSM notification");

		ContainerReference src = noti.getObservedContainer();
		logger.debug("src getId(): " + src.getId() + " op.name(): " + op.name());
		
		// Zuerst zwischen WRITE und den anderen Operationen unterscheiden
		// bei WRITE ist das eigentliche Objekt noch in Entry() gekapselt
		
		if (op.name() == "WRITE") {
			for (Serializable e: entries) {
				Serializable s = ((Entry) e).getValue();
				if (s instanceof Gruppe) {
					Gruppe g = (Gruppe) s;
					int index = view.getGroupSystemModel().indexOf(g);
					if (index < 0)
						view.getGroupSystemModel().addElement(g);
					else
						view.getGroupSystemModel().set(index, g);
				}
			}
		}
		
/*		if (op.name() == "TAKE") {
			for (Serializable s: entries) {
				if (s instanceof Gruppe) {
					Gruppe g = (Gruppe) s;
					view.getGroupSystemModel().removeElement(g);
				}
			}
		}
*/
	}

	@Override
	public void windowActivated(WindowEvent arg0) {
		
	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		
	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		logger.info("Shutdown der Threads beginnt.");
		for (Thread t: threads) {
			if (t.isAlive())
				t.interrupt();
			try {
				t.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		logger.info("Shutdown der Threads beendet, Shutdown von XVMS beginnt.");
		filiale1.getNotificationManager().shutdown();
		filiale2.getNotificationManager().shutdown();
		filiale1.getCore().shutdown(true);
		filiale2.getCore().shutdown(true);
		logger.info("Shutdown abgeschlossen.");
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		
	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		
	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		
	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("Send queue to Space"))
			sendGroupsToSpace();
	}
}
